package cube

import (
	"database/sql"
	"fmt"
	"strconv"
	"sync"

	"shqsoft.cn/pasnj/base"
	"shqsoft.cn/pasnj/bi/database"
	"shqsoft.cn/pasnj/bi/dictionary"

	"github.com/go-redis/redis"
	log "github.com/sirupsen/logrus"
)

var insts map[string]*Share

var m *sync.RWMutex

func init() {
	m = new(sync.RWMutex)
	insts = make(map[string]*Share)
}

//Share 员工当前分配
type Share struct {
	redisCli *redis.Client
	hkey     string
	lkey     string
	skey2    string
	lkey2    string
	keyCol   string
	diviCol  string
	empl     *dictionary.Employee
}

//GetShare 获取员工分配
func GetShare(shareType string) (share *Share, err error) {
	var ok bool
	share, ok = insts[shareType]
	if !ok {
		m.Lock()
		defer m.Unlock()
		share, err = newShare(shareType)
		if err != nil {
			return nil, err
		}
		insts[shareType] = share
	}
	return
}

//NewShare 员工分配
func newShare(shareType string) (share *Share, err error) {
	var hkey, lkey, skey2, lkey2 string
	keyCol := "ACID"
	diviCol := "DSVL"
	switch shareType {
	case "comp_acco_divi":
		hkey = "dc:h:"
		lkey = "dc:l:"
		skey2 = "dc2:h:"
		lkey2 = "dc2:l:"
	case "comp_acco_oper":
		hkey = "dim:h:"
		lkey = "dim:l:"
		skey2 = "dim2:h:"
		lkey2 = "dim2:l:"
	case "comp_clie_divi":
		hkey = "dcc:h:"
		lkey = "dcc:l:"
		skey2 = "dcc2:h:"
		lkey2 = "dcc2:l:"
		keyCol = "CUID"
	case "indi_acco_divi":
		hkey = "dis:h:"
		lkey = "dis:l:"
		skey2 = "dis2:h:"
		lkey2 = "dis2:l:"
	case "indi_fana_divi":
		hkey = "dif:h:"
		lkey = "dif:l:"
		skey2 = "dis2:h:"
		lkey2 = "dis2:l:"
	case "indi_loan_divi":
		hkey = "dil:h:"
		lkey = "dil:l:"
		skey2 = "dil2:h:"
		lkey2 = "dil2:l:"
	case "indi_clie_divi":
		hkey = "dic:h:"
		lkey = "dic:l:"
		skey2 = "dic2:h:"
		lkey2 = "dic2:l:"
		keyCol = "CUID"
		diviCol = "BSVL"
	case "comp_qtzb_divi":
		hkey = "dcq:h:"
		lkey = "dcq:l:"
		skey2 = "dcq2:h:"
		lkey2 = "dcq2:l:"
		keyCol = "YWID"
		diviCol = "DSVL"
	case "indi_qtzb_divi":
		hkey = "diq:h:"
		lkey = "diq:l:"
		skey2 = "diq2:h:"
		lkey2 = "diq2:l:"
		keyCol = "YWID"
		diviCol = "DSVL"

	default:
		return nil, fmt.Errorf("指定的员工分配类型%s不存在！", shareType)
	}
	share = &Share{
		redisCli: base.RedisClients[0],
		hkey:     hkey,
		lkey:     lkey,
		skey2:    skey2,
		lkey2:    lkey2,
		keyCol:   keyCol,
		diviCol:  diviCol,
		empl:     dictionary.NewEmployee(),
	}
	return
}

func (s *Share) getTableName() string {
	pref := string(([]byte(s.hkey))[:3])
	var tName string
	switch pref {
	case "dc:":
		tName = "divi_comp_acco"
	case "dcc":
		tName = "divi_comp_clie"
	case "dis":
		tName = "divi_indi_acco"
	case "dif":
		tName = "divi_indi_fana"
	case "dil":
		tName = "divi_indi_loan"
	case "dic":
		tName = "divi_indi_clie"
	case "dcq":
		tName = "divi_comp_qtzb"
	case "diq":
		tName = "divi_indi_qtzb"
	case "dim":
		tName = "divi_comp_oper"
	}
	return tName
}

//Build 构建
func (s *Share) Build() error {
	err := s.delete()
	if err != nil {
		return err
	}
	tName := s.getTableName()
	log.Infof("开始构建分户表:%s", tName)
	dl := database.DefaultDataLoader
	rows, err := dl.LoadDataByProc(tName)
	if err != nil {
		return err
	}
	defer rows.Close()
	cols, err := base.GetColumns(rows)
	if err != nil {
		return err
	}
	clen := len(cols)
	values := make([]sql.NullString, clen)
	scanArgs := make([]interface{}, clen)
	for i := 0; i < clen; i++ {
		scanArgs[i] = &values[i]
	}
	for rows.Next() {
		err := rows.Scan(scanArgs...)
		if err != nil {
			return err
		}
		if err := s.addData(base.ToMap(cols, values)); err != nil {
			return err
		}
	}
	log.Infof("构建分户表:%s完成", tName)
	return nil
}
func (s *Share) addData(data map[string]interface{}) error {
	tName := s.getTableName()
	key, ok := data[s.keyCol]
	if !ok {
		return fmt.Errorf("给定的表%s中不存在字段%s", tName, s.keyCol)
	}
	emid, ok := data["EMID"]
	if !ok {
		return fmt.Errorf("给定的表%s中不存在字段EMID", tName)
	}
	keyStr := base.ToString(key)
	field := base.ToString(emid)
	dsvl := data[s.diviCol]
	hkey := s.hkey + ":" + keyStr
	find := s.redisCli.Exists(hkey).Val()
	if find == 0 {
		if err := s.redisCli.RPush(s.lkey, keyStr).Err(); err != nil {
			return err
		}
	}
	if err := s.redisCli.HSet(hkey, field, dsvl).Err(); err != nil {
		return err
	}
	skey2 := s.skey2 + ":" + field
	find = s.redisCli.Exists(skey2).Val()
	if find == 0 {
		if err := s.redisCli.RPush(s.lkey2, field).Err(); err != nil {
			return err
		}
	}
	if err := s.redisCli.SAdd(skey2, keyStr).Err(); err != nil {
		return err
	}
	return nil
}

//GetDivision 获取业务认定关系
func (s *Share) GetDivision(key string) (map[string]float64, error) {
	divi, err := s.redisCli.HGetAll(s.hkey + ":" + key).Result()
	if err != nil {
		return nil, err
	}
	retDivi := make(map[string]float64)
	var val float64
	for k, v := range divi {
		val, err = strconv.ParseFloat(v, 64)
		if err != nil {
			return nil, fmt.Errorf("占比值%s不是数字！", v)
		}
		ki, _ := strconv.Atoi(k)
		name, err := s.empl.GetNameByID(ki)
		if err != nil {
			return nil, err
		}
		retDivi[name] = val * 100
	}
	return retDivi, nil
}

//Delete 清除Index缓存
func (s *Share) delete() error {
	if err := deleteByList(s.redisCli, s.hkey+":", s.lkey); err != nil {
		return err
	}
	if err := deleteByList(s.redisCli, s.skey2+":", s.lkey2); err != nil {
		return err
	}
	if err := s.redisCli.Del(s.lkey).Err(); err != nil {
		return err
	}
	if err := s.redisCli.Del(s.lkey2).Err(); err != nil {
		return err
	}
	return nil
}
